﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using LPPA.Facturacion.BizEntities;
using LPPA.Facturacion.DataAccess;
using LPPA.Facturacion.Services.Logger;

namespace LPPA.Facturacion.BusinessLayer
{
    public static class MedidorService
    {
        #region Private Methods

        /// <summary>
        /// Convierte MedidorBIZ a una entidad Medidor.
        /// </summary>
        /// <param name="MedidorBIZ"></param>
        /// <returns></returns>
        private static Medidor BIZtoEntity(MedidorBIZ MedidorBIZ)
        {
            try
            {
                return new LPPA.Facturacion.DataAccess.Medidor()
                            {
                                Calle = MedidorBIZ.Calle,
                                Altura = MedidorBIZ.Altura,
                                Nro_Medidor = MedidorBIZ.NumeroMedidor,
                                TipoMedidor = MedidorBIZ.TipoMedidor,
                                Titular = MedidorBIZ.Titular.CodigoTitular
                            };
            }
            catch (Exception ex)
            {
                LogManager.WriteError("Error al convertir un MedidorBIZ en Medidor.", ex.StackTrace);
                throw;
            }
        }

        /// <summary>
        /// Convierte una entidad Medidor en un objeto Medidor BIZ.
        /// </summary>
        /// <param name="MedidorToConvert"></param>
        /// <returns></returns>
        private static MedidorBIZ ToBIZ(Medidor MedidorToConvert)
        {
            try
            {
                 return new MedidorBIZ()
            {
                Titular = new TitularService().GetById(MedidorToConvert.Titular),
                Altura = MedidorToConvert.Altura,
                Calle = MedidorToConvert.Calle,
                TipoMedidor = MedidorToConvert.TipoMedidor,
                NumeroMedidor = MedidorToConvert.Nro_Medidor,
                NombreTitular = MedidorToConvert.Titular1.Nombre, 
                TipoMedidorDisplay = (MedidorToConvert.TipoMedidor == 1) ? "Reactivo" : "Reactivo-Inductivo"
            };
            }
            catch (Exception ex)
            {
                LogManager.WriteError("Error al convertir un Medidor en un MedidorBIZ.", ex.StackTrace);
                throw;
            }
        }

        #endregion

        #region Gets
        /// <summary>
        /// Retorna una Lista de Medidores según el Código del Titular.
        /// </summary>
        /// <param name="CodigoTitular"></param>
        /// <returns></returns>
        public static List<MedidorBIZ> GetMedidoresByTitular(int CodigoTitular)
        {
            try
            {
                List<MedidorBIZ> _ListMedidorReturn = new List<MedidorBIZ>();
                using (DataAccess.dcEdenorteDataContext context = new DataAccess.dcEdenorteDataContext())
                {
                    var medidores = (from m in context.Medidors
                                     where m.Titular == CodigoTitular
                                     select m);

                    foreach (var item in medidores)
                    {
                        _ListMedidorReturn.Add(ToBIZ(item));
                    }

                    return _ListMedidorReturn;
                }
            }
            catch (Exception ex)
            {
                LogManager.WriteError("Error al Obtener los medidores de un titular.", ex.StackTrace);
                throw;
            }
        }

        /// <summary>
        /// Retorna una lista con todos los Medidores existentes.
        /// </summary>
        /// <returns></returns>
        public static List<MedidorBIZ> GetAll()
        {
            try
            {
                List<MedidorBIZ> _ListMedidorReturn = new List<MedidorBIZ>();
                using (DataAccess.dcEdenorteDataContext context = new DataAccess.dcEdenorteDataContext())

                {
                    var medidores = (from m in context.Medidors
                                     select m);

                    foreach (var item in medidores)
                    {
                        _ListMedidorReturn.Add(ToBIZ(item));
                    }

                    return _ListMedidorReturn;
                }
            }
            catch (Exception ex)
            {
                LogManager.WriteError("Error al obtener todos los medidores.", ex.StackTrace);
                throw;
            }
        }

        /// <summary>
        /// Retorna una lista con todos los Medidores existentes segun Filtro ( titular, calle).
        /// </summary>
        /// <returns></returns>
        public static List<MedidorBIZ> GetAllByFilter(string Filter)
        {
            try
            {
                List<MedidorBIZ> _ListMedidorReturn = new List<MedidorBIZ>();
                using (DataAccess.dcEdenorteDataContext context = new DataAccess.dcEdenorteDataContext())
                {
                    var medidores = (from m in context.Medidors
                                     select m).Where(m=> m.Nro_Medidor.ToString() == Filter 
                                                        || m.Calle.Contains(Filter)) ;

                    foreach (var item in medidores)
                    {
                        _ListMedidorReturn.Add(ToBIZ(item));
                    }

                    return _ListMedidorReturn;
                }
            }
            catch (Exception ex)
            {
                LogManager.WriteError("Error al obtener todos los medidores.", ex.StackTrace);
                throw;
            }
        }

        /// <summary>
        /// Retorna una lista con todos los Medidores instalados en cierta calle.
        /// </summary>
        /// <param name="Calle"></param>
        /// <returns></returns>
        public static List<MedidorBIZ> GetAllByCalle(string Calle)
        {
            try
            {
                List<MedidorBIZ> _ListMedidorReturn = new List<MedidorBIZ>();
                using (DataAccess.dcEdenorteDataContext context = new DataAccess.dcEdenorteDataContext())
                {
                    var medidores = (from m in context.Medidors
                                     where m.Calle.ToLower().Contains(Calle.ToLower())
                                     select m);

                    foreach (var item in medidores)
                    {
                        _ListMedidorReturn.Add(ToBIZ(item));
                    }

                    return _ListMedidorReturn;
                }
            }
            catch (Exception ex)
            {
                LogManager.WriteError("Error al Obtener todos los medidores instalados en una calle.", ex.StackTrace);
                throw;
            }
        }

        /// <summary>
        /// Retorna una lista con todos los Medidores instalados en cierta calle y entre un rango de alturas.
        /// </summary>
        /// <param name="Calle"></param>
        /// <param name="AlturaInicial"></param>
        /// <param name="AlturaFinal"></param>
        /// <returns></returns>
        public static List<MedidorBIZ> GetAllByCalleRangoAlturas(string Calle, int AlturaInicial, int AlturaFinal)
        {
            try
            {
                List<MedidorBIZ> _ListMedidorReturn = new List<MedidorBIZ>();
                using (DataAccess.dcEdenorteDataContext context = new DataAccess.dcEdenorteDataContext())
                {
                    var medidores = (from m in context.Medidors
                                     where m.Calle.ToLower().Contains(Calle.ToLower()) &&
                                     (AlturaInicial < m.Altura) &&
                                     (AlturaFinal > m.Altura)
                                     select m);

                    foreach (var item in medidores)
                    {
                        _ListMedidorReturn.Add(ToBIZ(item));
                    }

                    return _ListMedidorReturn;
                }
            }
            catch (Exception ex)
            {
                LogManager.WriteError("Error al Obtener todos los medidores instalados en una calle y rango de alturas.", ex.StackTrace);
                throw;
            }
        }

        /// <summary>
        /// Obtiene un Medidor según su Número de Medidor.
        /// </summary>
        /// <param name="NumeroMedidor"></param>
        /// <returns></returns>
        public static MedidorBIZ GetMedidorByNumeroMedidor(int NumeroMedidor)
        {
            try
            {
                using (DataAccess.dcEdenorteDataContext context = new DataAccess.dcEdenorteDataContext())
                {
                    var medidores = (from m in context.Medidors
                                     where m.Nro_Medidor == NumeroMedidor
                                     select m);


                    return ToBIZ(medidores.SingleOrDefault());
                }
            }
            catch (Exception ex)
            {
                LogManager.WriteError("Error al Obtener un medidor segun su numero.", ex.StackTrace);
                throw;
            }
        }
        #endregion

        #region CRUD Operations

        /// <summary>
        /// Insert Medidor.
        /// </summary>
        /// <param name="MedidorNew"></param>
        /// <returns></returns>
        public static int Insert(MedidorBIZ MedidorNew)
        {
            try
            {
                using (DataAccess.dcEdenorteDataContext context = new DataAccess.dcEdenorteDataContext())
                {
                    var medidorToInsert = BIZtoEntity(MedidorNew);
                    context.Medidors.InsertOnSubmit(medidorToInsert);

                    context.SubmitChanges();
                    return medidorToInsert.Nro_Medidor;
                }
            }
            catch (Exception ex)
            {
                LogManager.WriteError("Error al intentar crear un medidor.", ex.StackTrace);
                throw;
            }
        }

        /// <summary>
        /// Actualizar Medidor.
        /// </summary>
        /// <param name="MedidorUpdated"></param>
        public static void Update(MedidorBIZ MedidorUpdated)
        {
            try
            {
                using (DataAccess.dcEdenorteDataContext context = new DataAccess.dcEdenorteDataContext())
                {

                    var medidor = (from m in context.Medidors
                                   where m.Nro_Medidor == MedidorUpdated.NumeroMedidor
                                   select m).SingleOrDefault();

                    medidor.Calle = MedidorUpdated.Calle;
                    medidor.Altura = MedidorUpdated.Altura;
                    medidor.Nro_Medidor = MedidorUpdated.NumeroMedidor;
                    medidor.TipoMedidor = MedidorUpdated.TipoMedidor;


                    context.SubmitChanges();
                }
            }
            catch (Exception ex)
            {
                LogManager.WriteError("Error al actualizar un medidor.", ex.StackTrace);
                throw;
            }
        }
        #endregion

        public static string GetNewId()
        {
            try
            {
                using (DataAccess.dcEdenorteDataContext context = new DataAccess.dcEdenorteDataContext())
                {

                    var medidor = (from m in context.Medidors
                                   orderby m.Nro_Medidor descending
                                   select m.Nro_Medidor).Take(1).SingleOrDefault();
                    
                    return (medidor + 1).ToString();
                }
            }
            catch (Exception ex)
            {
                LogManager.WriteError("Error al actualizar un medidor.", ex.StackTrace);
                throw;
            }
        }
    }
}
